from os import environ, system
from datetime import date
from time import strftime, localtime, sleep
from shutil import copyfileobj
from re import split as splitr, findall
from uuid import uuid4

from requests import get
from bs4 import BeautifulSoup

from .funcs import checkPathResources, loadImage, singleNotify, countPercent


class ParseAnime():
    """ Getting data about anime. """
    def __init__(self):
        super(ParseAnime, self).__init__()
        self.current_path = f'{environ["HOME"]}/.cache/anima'
        self.percent, self.dead = 0, False

    def __checkEnded(self, txt: str, num: int, end: str) -> str:
        """ Checking ongoing of anime to ended. """
        raw = findall(r'\[.*\d+\]', txt)
        if raw:
            raw = raw[0].split(']')[0].split(' из ')[1]
            check = True if '+' in raw or \
                            num < int(raw.split('+')[0]) else False
            return 'ongoing' if check else 'end'
        return end

    def __numCheck(self, data, mass, ova, series, name, index, check=False):
        """ Validation of received data from the request. """
        inti = mass[-1].split()
        ind = -1 if len(mass) == 2 else -2 if len(mass) == 3 else -3
        if len(mass) == 2 or len(mass) == 1:
            arr = -1 if 'Анонс' in mass[-1] else int(mass[-1].split()[0]) \
                if '-' not in mass[-1] else \
                int(mass[-1].split()[0].split('-')[1])
        else:
            arr = int(mass[ind].split()[0].split('-')[1]) \
                if '-' in mass[ind] else -1 if 'Анонс' in mass[ind] else \
                mass[ind][:1:]
        int_i = int(inti[1]) if 'ОВА 1 из' in mass[-1] else \
                int(inti[1].split('-')[1]) if 'ОВА 1-' in mass[-1] else 0

        num = arr if isinstance(arr, int) else int(arr[-1].split()[0])
        c_d = date.today()
        c_t = strftime("%H:%M", localtime())
        note = f'[A][{c_d.day}/{c_d.month}/{c_d.year} - {c_t}] > {name}'
        txt = f'{note} - new series {num} & new ova-{int_i}' \
            if num >= series and ova <= int_i else \
            f'{note} - new series {num}' if num >= series and \
            ova != int_i else f'{note} - new ova-{int_i}' \
            if ova <= int_i and series != num else ""
        if txt:
            data['notify']['anime'] = singleNotify(data['notify']['anime'],
                                                   name)
            data['notify']['anime'].append(txt)
            data['anime']['look'][index] = num
            data['anime']['ova'][index] = int_i
            check = True
        return check, data

    def checkRelease(self, data, led, count=0):
        """ Quick check for new releases. """
        link = get('https://animevost.org')
        led.setToolTip('Tracking: animevost')
        soup = BeautifulSoup(link.text, 'html.parser')
        raspisanie = soup.find_all('ul', class_='raspis_fixed')
        links = raspisanie[0].find_all("a")
        txt = [i.split(' / ') for i in raspisanie[0].text.split('\n')[1:-1:]]
        link = [links[i[0]]["href"] for i in enumerate(txt)]
        fz = [splitr('\d-', i)[1].split('.')[0] for i in data['anime']['urls']]
        for i,v in enumerate(link):
            for c,j in enumerate(fz):
                if j in v:
                    mass = txt[i][1].split('[')
                    check, data = self.__numCheck(data, mass,
                                data['anime']['ova'][c]+1,
                                data['anime']['series'][c]+1, txt[i][0], c)
                    count += 1 if check else 0
                    data['anime']['ended'][c] = self.__checkEnded(txt[i][1],
                                                    data['anime']['look'][c],
                                                    data['anime']['ended'][c])
        return [' / '.join(i) for i in txt], link, data, count

    def __check(self, data, url, series, ova, index, check=False):
        """ More accurate check of the release of new series. """
        soup = BeautifulSoup(get(url).text, 'html.parser')
        names = soup.find('div',
                    class_='shortstoryHead').text[22:-18:].split(' / ')
        name = names[0]
        mass = names[1].split('[')
        check, data = self.__numCheck(data, mass, ova, series, name, index)
        data['anime']['ended'][index] = self.__checkEnded(names[1],
                                            data['anime']['look'][index],
                                            data['anime']['ended'][index])
        return name, check, soup, data

    def __full(self, soup):
        """ Getting more data on anime. """
        desc = soup.find_all('p')
        fuzy_name = soup.find('div',
                class_='shortstoryHead').text[22:-18:].split(' / ')[0]
        name = "_".join(fuzy_name.split())
        description = desc[7].text if len(desc) == 10 else desc[8].text
        img = soup.find_all('img', class_='imgRadius')[0]["src"]
        image = f'https://www.animevost.org{img}'
        img = img.split('/')
        checkPathResources()
        r = get(image, stream=True)
        if r.status_code == 200:
            name = str(uuid4()) if len(name) > 127 else name
            with open(f'{self.current_path}/description/raw/{name}_{img[-1]}',
                      'wb') as f:
                r.raw.decode_content = True
                copyfileobj(r.raw, f)

        image = loadImage(f'{name}_{img[-1]}') or 'icons/animevost.png'
        return image, description

    def __iteration(self, data, url, ind, check=False, flag=False):
        name, check, soup, data = self.__check(data, url,
                                         data['anime']['series'][ind]+1,
                                         data['anime']['ova'][ind]+1,
                                         ind, check)
        if flag:
            full = (name, *self.__full(soup))
            for i, v in enumerate(('name', 'images', 'description')):
                data['anime'][v][ind] = full[i]
        else:
            data['anime']['name'][ind] = name
        return data, check

    def run(self, data, flag):
        count = 0
        self.default()
        for i, v in enumerate(data['anime']['urls']):
            try:
                self.percent = countPercent(i, len(data['anime']['urls']))
                if self.dead: break
                if data['anime']['name'][i] and \
                   'description' in data['anime']['images'][i] and \
                   data['anime']['description'][i] and flag or \
                   data['anime']['ended'][i] == 'end':
                    sleep(.1 if len(data['anime']['urls']) // 60 > 0 else .4)
                    continue
                data, check = self.__iteration(data, v, i, flag=flag)
                count += 1 if check else 0
            except Exception as e:
                system(f'notify-send "Error for anime {flag}\n{e}"')

        return data, (count, 0)

    def default(self):
        self.percent, self.dead = 0, False

    def getPercent(self):
        return self.percent

    def breaking(self):
        self.dead = True
